package com.le.tester.webpage.WXPay.service.impl;

import com.github.wxpay.sdk.WXPayConfig;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.le.tester.utils.HttpUtil;
import com.le.tester.utils.IPUtil;
import com.le.tester.utils.PayUtil;
import com.le.tester.webpage.WXPay.dto.WxPayDto;
import com.le.tester.webpage.WXPay.entiry.WxPay;
import com.le.tester.webpage.WXPay.service.PayInfoService;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 描述：支付的实现层
 */
@Service
public class PayInfoServiceImpl implements PayInfoService {
    private static final Logger LOG = LoggerFactory.getLogger(PayInfoServiceImpl.class);

    @Autowired
    private Environment env;

    @Autowired
    private HttpServletRequest request;


    @Override
    public WxPay getPayInfoByOrderNo(String ownOrderNo) {
        WxPay wxPay = new WxPay();
        wxPay.setOpenId("wxOpenId");
        wxPay.setPrice(new BigDecimal("1100"));
        return wxPay;
    }

    @Override
    public void saveWxPayInfo(WxPay wxPay) {

    }


    private Map<String, String> assembleWxPayInfo() throws Exception {
        //测试的商品名称
        String productName = "测试商品名称";
        //客户端的地址
        String ipAddress = IPUtil.getIpAddress(request);

        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("appid", env.getProperty("wxPay.appid"));
        resultMap.put("mch_id", env.getProperty("wxPay.mch_id"));
        resultMap.put("nonce_str", WXPayUtil.generateNonceStr());
        resultMap.put("body", productName);
        resultMap.put("out_trade_no", "1122");
        resultMap.put("total_fee", "1100");
        resultMap.put("notify_url", env.getProperty("wxPay.notify_url"));// 支付成功后的回调地址
        resultMap.put("trade_type", env.getProperty("wxPay.TRADETYPE"));// 支付方式
        resultMap.put("openid", "2233");// 微信openid
        resultMap.put("spbill_create_ip", ipAddress);// 客户端的ip地址
        //生成签名
        String sign = WXPayUtil.generateSignature(resultMap, env.getProperty("wxPay.key"));
        resultMap.put("sign", sign);
        return resultMap;
    }

    //xml数据生成，获取返回的xml信息
    private String generalPreStr() throws Exception {
        //获取支付的信息
        Map<String, String> wxPayInfo = this.assembleWxPayInfo();

        //变成一个长的字符串，k1->v1,用&拼接字符串
        String preStr = PayUtil.createLinkString(wxPayInfo);
        //生成签名
        String sign = PayUtil.sign(preStr, env.getProperty("wxPay.key"), "utf-8").toUpperCase();
        // 拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
        String requestXml = "<xml>" + "<appid>" + env.getProperty("wxPay.appid") + "</appid>" + "<body><![CDATA[" + wxPayInfo.get("body") + "]]></body>"
                + "<mch_id>" + env.getProperty("wxPay.mch_id") + "</mch_id>" + "<nonce_str>" + wxPayInfo.get("nonce_str") + "</nonce_str>"
                + "<notify_url>" + env.getProperty("wxPay.notify_url") + "</notify_url>" + "<openid>" + wxPayInfo.get("openid") + "</openid>"
                + "<out_trade_no>" + wxPayInfo.get("out_trade_no") + "</out_trade_no>" + "<spbill_create_ip>" + wxPayInfo.get("spbill_create_ip")
                + "</spbill_create_ip>" + "<total_fee>" + wxPayInfo.get("total_fee") + "</total_fee>" + "<trade_type>"
                + env.getProperty("wxPay.TRADETYPE") + "</trade_type>" + "<sign>" + sign + "</sign>" + "</xml>";

        LOG.info("调试模式_统一下单接口 请求XML数据:{}", requestXml);
        //获取响应的数据，也是xml
        String responseXmlData = PayUtil.httpRequest(env.getProperty("wxPay.pay_url"), "POST", requestXml);

        LOG.info("调试模式_统一下单接口 响应的XML数据:{}", responseXmlData);
        return responseXmlData;
    }

    //解析获取的xml信息
    @Override
    public Map<String, Object> deployPay() throws Exception {
        String xmlStr = this.generalPreStr();

        Map<String, String> wxPayInfo = this.assembleWxPayInfo();
        //保存响应的数据
        Map map = PayUtil.doXMLParse(xmlStr);
        String returnCode = String.valueOf(map.get("return_code"));

        Map<String, Object> response = new HashMap<>();
//        if ("SUCCESS".equals(returnCode)) {
        if ("null".equals(returnCode)) {
            //返回的预支付订单消息
            String prepayId = String.valueOf(map.get("prepay_id"));
            response.put("nonceStr", wxPayInfo.get("nonce_str"));
            response.put("package", "prepayId=" + prepayId);
            Long timeStamp = System.currentTimeMillis() / 1000;
            //将返回的时间转成时间戳
            response.put("timeStamp", String.valueOf(timeStamp));
            //拼接签名需要的参数
            String stringSignTemp = "appId=" + env.getProperty("wxPay.appid") + "&nonceStr=" + wxPayInfo.get("nonce_str") + "&package=prepay_id="
                    + prepayId + "&signType=MD5&timeStamp=" + timeStamp;
            // 再次签名，这个签名用于小程序端调用wx.requesetPayment方法
            String paySign = PayUtil.sign(stringSignTemp, env.getProperty("wxPay.key"), "utf-8").toUpperCase();
            response.put("paySign", paySign);
        }
        response.put("appid", env.getProperty("wxPay.appid"));

        return response;
    }

    //微信支付回调
    @Override
    @SuppressWarnings("unchecked")
    public String wxPayNotify() throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line = null;
        StringBuilder stringBuilder = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
        }
        reader.close();
        String resXml = null;
        //获取了微信响应的报文
        String notifyXml = String.valueOf(stringBuilder);
        LOG.info("接收到的报文，{}", notifyXml);

        Map map = PayUtil.doXMLParse(notifyXml);
        //获取响应码
        String returnCode = String.valueOf(map.get("return_code"));

        if ("SUCCESS".equals(returnCode)) {
            Map<String, String> paraFilter = PayUtil.paraFilter(map);
            String linkString = PayUtil.createLinkString(paraFilter);
            String sign = PayUtil.sign(linkString, env.getProperty("wxPay.key"), "utf-8").toUpperCase();
            if (sign.equals(map.get("sign"))) {
                // 通知微信服务器已经支付成功
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[sign error]]></return_msg>" + "</xml> ";
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        System.out.println(resXml);
        System.out.println("微信支付回调数据结束");

        return resXml;


    }

    //优化的微信支付
    @Override
    public Map<String, Object> deployWxPay(WxPayDto wxPayDto) throws Exception {

        Map<String, Object> resultMap = new HashMap<>();
        Map<String, String> payMap = new HashMap<>();
//        获取预下单的数据
        Map<String, String> assembleWxPayInfo = this.assembleWxPayInfo();
        // 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder

        String unifiedOrderUrl = env.getProperty("wxPay.UNIFIED_ORDER_URL");
        //将map装换成xml
        String toXml = WXPayUtil.mapToXml(assembleWxPayInfo);
        //String toXml = PayUtil.createLinkString(assembleWxPayInfo);
        //对微信进行请求(会返回xml)
        //把xml转成json

        String responseXml = HttpUtil.post(unifiedOrderUrl, toXml);
        Map<String, String> toMap = WXPayUtil.xmlToMap(responseXml);

        //返回的不是success
        if (!(WXPayConstants.SUCCESS.equalsIgnoreCase(toMap.get("return_code")))) {
            resultMap.put("code", toMap.get("return_code"));
            resultMap.put("msg", toMap.get("return_msg"));
            return resultMap;
        }
        //调用成功后的处理(组装返回的数据)
        //获取两个小时有效期的预支付订单
        String prepayId = toMap.get("prepay_id");

        payMap.put("appid", env.getProperty("wxPay.appid"));
        payMap.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
        payMap.put("nonceStr", WXPayUtil.generateNonceStr());
        payMap.put("signType", env.getProperty("wxPay.signType"));
        payMap.put("package", "prepay_id" + prepayId);

        //再生成支付sign
        String paySign = WXPayUtil.generateSignature(payMap, env.getProperty("wxPay.key"));
        payMap.put("paySign", paySign);
        payMap.put("outTradeNo", assembleWxPayInfo.get("out_trade_no"));
        resultMap.put("data", payMap);
        resultMap.put("code", 200);
        resultMap.put("msg", "success");
        return resultMap;
    }

    //微信支付回调优化
    @Override
    public String wxPayNotifyBetter(WxPayDto wxPayDto) throws Exception {
        //获取一下接收到的报文
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
        StringBuilder stringBuilder = new StringBuilder();
        String line = null;
        String resXml = null;
        while ((line = bufferedReader.readLine()) != null) {
            stringBuilder.append(line);
        }
        bufferedReader.close();
        String resForWxPayNotify = String.valueOf(stringBuilder);
        LOG.info("接收到的微信支付报文:{}", resForWxPayNotify);

        //需要将收到的xml报文转换成map
        Map<String, String> xmlToMap = WXPayUtil.xmlToMap(resForWxPayNotify);
        //1.验证返回的状态码
        if ((WXPayConstants.SUCCESS.equalsIgnoreCase(xmlToMap.get("return_code")))) {
            LOG.info("微信支付回调成功");
            //2.验证sign
            if (WXPayUtil.isSignatureValid(xmlToMap, env.getProperty("wxPay.key"))) {
                LOG.info("验证 sign is success");
                resXml = env.getProperty("wxPay.resSuccessXml");
            } else {
                LOG.info("验证 sign is error");
                resXml = env.getProperty("wxPay.resSignFailXml");
            }
        } else {
            LOG.info("微信支付回调失败");
            resXml = env.getProperty("wxPay.resFailXml");
        }
        //3.根据订单号码进行业务逻辑的处理
        LOG.info("需要处理的订单号：{}", xmlToMap.get("out_trade_no"));

        //可以根据订单号码进行订单状态的更新updateOrderStatusByOrderNo

        return resXml;
    }


}
